import { CommonModule } from '@angular/common';
import { HttpClient } from '@angular/common/http';
import {
  ChangeDetectionStrategy,
  Component,
  DestroyRef,
  ViewChild,
  computed,
  forwardRef,
  inject,
  input,
  output,
  signal,
} from '@angular/core';
import {
  AbstractControl,
  ControlValueAccessor,
  FormControl,
  NG_VALIDATORS,
  NG_VALUE_ACCESSOR,
  ReactiveFormsModule,
  ValidationErrors,
  Validator,
} from '@angular/forms';
import { TuiAlertService } from '@taiga-ui/core';
import { TuiFileLike, TuiFiles, TuiInputFiles } from '@taiga-ui/kit';
import {
  Observable,
  catchError,
  delay,
  finalize,
  of,
  switchMap,
  tap,
} from 'rxjs';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { OssService } from '../../services/oss.service';
import {
  DeleteIconComponent,
  UploadIconComponent,
  ViewIconComponent,
} from '../../shared/icons';
import { ImagePreviewComponent } from '../../shared/components/image-preview/image-preview.component';

// OSS配置接口
export interface OssParams {
  key?: string;
  policy?: string;
  signature?: string;
  ossAccessKeyId?: string;
  dir?: string;
  host?: string;
  expire?: number;
  [key: string]: unknown;
}

// 上传配置接口
export interface UploadConfig {
  useCustomUploader?: boolean;
  action?: string;
  uploadFileName?: string;
  ossParams?: OssParams;
  responseProcessor?: (response: any) => string;
}

@Component({
  selector: 'app-super-upload',
  standalone: true,
  imports: [
    CommonModule,
    ReactiveFormsModule,
    TuiFiles,
    TuiInputFiles,
    UploadIconComponent,
    ViewIconComponent,
    DeleteIconComponent,
    ImagePreviewComponent,
  ],
  templateUrl: './upload.component.html',
  styleUrl: './upload.component.less',
  changeDetection: ChangeDetectionStrategy.OnPush,
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => SuperUploadComponent),
      multi: true,
    },
    {
      provide: NG_VALIDATORS,
      useExisting: forwardRef(() => SuperUploadComponent),
      multi: true,
    },
  ],
})
export class SuperUploadComponent implements ControlValueAccessor, Validator {
  private readonly alertService = inject(TuiAlertService);
  private readonly ossService = inject(OssService);
  private readonly http = inject(HttpClient);
  private readonly destroyRef = inject(DestroyRef);

  label = input<string>('点击或拖拽文件到此处上传');
  accept = input<string>('image/jpeg,image/png,image/gif,image/webp');
  maxFileSize = input<number>(5 * 1024 * 1024);
  disabled = input<boolean>(false);
  config = input<UploadConfig>({
    useCustomUploader: true,
    uploadFileName: 'file',
  });

  uploaded = output<string>();
  deleted = output<void>();
  error = output<string>();
  fileSelected = output<File>();

  @ViewChild(ImagePreviewComponent) imagePreview!: ImagePreviewComponent;

  filesControl = new FormControl<TuiFileLike | null>(null);
  preview = signal<string | null>(null); // 存储图片URL和预览URL
  showPreview = signal<boolean>(false);
  isFileObject = signal<boolean>(false);
  isLoading = signal<boolean>(false);
  acceptString = computed(() => this.accept());

  maxSizeMB = computed(() => this.maxFileSize() / (1024 * 1024));

  // 表单控件接口实现
  private onChange: (value: string | null) => void = () => {};
  private onTouched: () => void = () => {};

  constructor() {
    // 监听文件变化
    this.filesControl.valueChanges
      .pipe(
        takeUntilDestroyed(this.destroyRef),
        tap((file) => this.handleFileChange(file))
      )
      .subscribe();
  }

  // 处理文件变化
  private handleFileChange(file: TuiFileLike | null): void {
    if (!file) {
      this.preview.set(null);
      this.isFileObject.set(false);
      return;
    }

    if (file instanceof File) {
      this.isFileObject.set(true);
      this.fileSelected.emit(file);

      if (!this.validateFile(file)) {
        this.filesControl.setValue(null, { emitEvent: false });
        return;
      }

      // 创建本地预览
      this.createLocalPreview(file);

      // 获取配置中的上传URL
      const config = this.config();
      let uploadUrl = config.action;

      // 检查OSS参数中的host
      if (config.ossParams?.host) {
        uploadUrl = config.ossParams.host;
      }

      // 只有在有上传URL时才上传文件
      if (uploadUrl) {
        this.uploadSelectedFile(file);
      } else {
        // 没有上传URL时，只进行本地预览，更新值并发送uploaded事件
        const previewUrl = this.preview();
        if (previewUrl) {
          this.updateValue(previewUrl);
          this.uploaded.emit(previewUrl);
        }
      }
    } else if (file.src) {
      this.isFileObject.set(false);
      this.preview.set(file.src as string);
    }
  }

  // 上传选中的文件
  private uploadSelectedFile(file: File): void {
    this.isLoading.set(true);

    this.uploadFile(file)
      .pipe(
        tap((url) => {
          if (url) {
            this.updatePreview(url);
            this.updateValue(url);
            this.uploaded.emit(url);
          }
        }),
        catchError((error) => {
          this.handleError('上传失败', error);
          this.error.emit(
            typeof error === 'string'
              ? error
              : error.message || '上传失败，请稍后重试'
          );
          // 上传失败时清除预览和值
          this.updatePreview(null);
          this.updateValue(null);
          return of(null);
        }),
        finalize(() => {
          this.isLoading.set(false);
        })
      )
      .subscribe();
  }

  // 创建本地预览
  private createLocalPreview(file: File): void {
    if (file.type.startsWith('image/')) {
      const url = URL.createObjectURL(file);
      this.preview.set(url);
    }
  }

  // ControlValueAccessor 接口实现
  writeValue(value: string | null): void {
    if (value !== this.preview()) {
      this.updatePreview(value);
    }
  }

  // 更新预览
  private updatePreview(url: string | null): void {
    if (url) {
      this.preview.set(url);
      this.filesControl.setValue(
        {
          name: this.getFileNameFromUrl(url),
          src: url,
        },
        { emitEvent: false }
      );
    } else {
      this.preview.set(null);
      this.filesControl.setValue(null, { emitEvent: false });
    }
  }

  registerOnChange(fn: (value: string | null) => void): void {
    this.onChange = fn;
  }

  registerOnTouched(fn: () => void): void {
    this.onTouched = fn;
  }

  setDisabledState(isDisabled: boolean): void {
    isDisabled ? this.filesControl.disable() : this.filesControl.enable();
  }

  // Validator 接口实现
  validate(control: AbstractControl): ValidationErrors | null {
    if (control.hasValidator(() => ({ required: true })) && !this.preview()) {
      return { required: true };
    }
    return null;
  }

  registerOnValidatorChange(fn: () => void): void {}

  // 上传文件
  private uploadFile(file: File): Observable<string | null> {
    const config = this.config();
    // 添加3秒延迟用于测试loading效果
    const delayTime = 3000;

    // 构建表单数据
    const formData = new FormData();
    formData.append(config.uploadFileName || 'file', file);

    // 确定上传URL
    let uploadUrl = config.action;

    // 处理OSS参数
    if (config.ossParams) {
      // 如果有host参数，使用它作为上传URL
      if (config.ossParams.host) {
        uploadUrl = config.ossParams.host;
      }

      // 将其他OSS参数添加到formData
      Object.entries(config.ossParams).forEach(([key, value]) => {
        if (key !== 'host' && value !== undefined && value !== null) {
          formData.append(key, String(value));
        }
      });
    }

    // 没有上传URL，返回错误
    if (!uploadUrl) {
      return of(null);
    }

    // 执行上传请求
    return this.http.post(uploadUrl, formData).pipe(
      switchMap((response) => {
        let url: string | null = null;

        // 使用自定义响应处理器
        if (config.responseProcessor) {
          try {
            url = config.responseProcessor(response);
          } catch (error) {
            console.error('处理响应错误:', error);
            throw new Error('处理上传响应时出错');
          }
        } else {
          console.log('response', response);

          // 默认响应处理器
          url = this.defaultResponseProcessor(response);
        }

        if (!url) {
          throw new Error('无法从响应中获取URL');
        }

        return of(url);
      }),
      catchError((error) => {
        console.error('上传请求错误:', error);
        throw error;
      }),
      delay(delayTime)
    );
  }

  // 默认响应处理器
  private defaultResponseProcessor(response: any): string {
    let url: string | null = null;

    // 处理对象响应
    if (response && typeof response === 'object') {
      if ('url' in response) {
        url = response.url as string;
      } else if (
        'data' in response &&
        typeof response.data === 'object' &&
        response.data &&
        'url' in response.data
      ) {
        url = response.data.url as string;
      }
    }
    // 处理字符串响应
    else if (typeof response === 'string') {
      url = response;
    }

    if (!url) {
      throw new Error('无法从响应中获取URL');
    }

    return url;
  }

  // 验证文件
  private validateFile(file: File): boolean {
    if (
      this.accept() &&
      !this.accept()
        .split(',')
        .some((type) => file.type === type.trim())
    ) {
      const message = `文件类型不支持，仅支持: ${this.accept()}`;
      this.handleError('文件验证失败', message);
      this.error.emit(message);
      return false;
    }

    if (file.size > this.maxFileSize()) {
      const message = `文件过大，最大允许: ${this.maxSizeMB()}MB (当前: ${(
        file.size /
        (1024 * 1024)
      ).toFixed(2)}MB)`;
      this.handleError('文件验证失败', message);
      this.error.emit(message);
      return false;
    }

    return true;
  }

  // 从URL获取文件名
  private getFileNameFromUrl(url: string): string {
    try {
      const urlParts = new URL(url).pathname.split('/');
      return urlParts[urlParts.length - 1] || 'file';
    } catch {
      return 'file';
    }
  }

  // 删除图片
  deleteImage(): void {
    this.updatePreview(null);
    this.updateValue(null);
    this.deleted.emit();
  }

  // 更新值
  updateValue(value: string | null): void {
    this.onChange(value);
    this.onTouched();
  }

  // 处理错误
  handleError(title: string, error: any): void {
    console.error(`${title}:`, error);
    this.alertService
      .open(typeof error === 'string' ? error : error.message || '请稍后重试', {
        label: title,
      })
      .subscribe();
  }

  // 打开图片预览
  openFullPreview(): void {
    if (this.preview()) {
      this.showPreview.set(true);
    }
  }

  // 关闭预览
  closePreview(): void {
    this.showPreview.set(false);
  }
}
